iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 7
0
自我挑戰組

JavaScript 30 挑戰日誌系列 第 8

Day 08:製作 Canvas 繪圖板!

  • 分享至 

  • xImage
  •  

作品 Demo 連結: 傳送門

作品目標:製作出繪圖板、並且筆觸粗細+顏色會隨時間改變!
難易度:★★★☆☆

前言

沒錯... 我的鐵人賽在第 7 天斷了!! QAQ

之前在瘋狂忙碌私事,連續熬了 48 小時趕工!!! (爆肝

最後好不容易結束,洗澡中想起還有鐵人賽!
秒衝去房間看時間... 00:08...
我整個人愣了大概有五秒吧...

不過,參與鐵人賽其實最主要的目的是可以督促我自己每天寫程式,
雖然斷掉了很可惜,不過現在更可以無壓力的去學習以及慢慢寫好文章,
我不會放棄的!! ˋAˊ//

也在此向所有偉大的鐵人們致敬! Orz


HTML (就一個 Canvas)

<canvas id="draw"></canvas>

CSS (就一行簡單 Reset!?)

html, body {
    margin:0;
}

【第一步:取得 Canvas 元素及渲染環境】

const canvas = document.querySelector('#draw');
const ctx = canvas.getContext('2d');  // 取得 Canvas 的渲染環境及其繪圖函數

想要在 canvas 內繪製圖畫一定要使用其渲染環境 Context
透過 Context 可以控制操作 Canvas 做任何的事情

【第二步:設定 Canvas 寬高滿版】

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

我相信這個沒什麼好解釋的...

【第三步:初始設定】

// Initialize
ctx.strokeStyle = '#bada55';  // 筆觸顏色
ctx.lineJoin = 'round';  // 兩條線交匯處產生 "圓形" 邊角
ctx.lineCap = 'round';  // 筆觸預設為 "圓形"
ctx.lineWidth = 1;  // 筆頭寬度

let isDrawing = false;  // 是否允許繪製  (或說是否是 mousedown 下筆狀態)

/* 繪製時的起點座標 */
let lastX = 0;
let lastY = 0;

透過 Context 去設定 顏色、形狀等等的細項

【第四步:繪圖函數撰寫(1)】

/*========== Events Binding ==========*/
canvas.addEventListener('mouseup', () => isDrawing = false);
canvas.addEventListener('mouseout', () => isDrawing = false);
canvas.addEventListener('mousedown', (e) => {
    isDrawing = true; // 允許繪製
    [lastX, lastY] = [e.offsetX, e.offsetY]; // 設定起始點
});

canvas.addEventListener('mousemove', draw);

/*========== 繪製函數;在 mousemove 的時候使用 ==========*/
function draw(e) {
    if(!isDrawing) return;  // 沒有允許繪製即退出

    /* 繪製路線 Setting */
    ctx.beginPath();  // 開始路徑 or Reset
    ctx.moveTo(lastX, lastY);  // 設定起點
    ctx.lineTo(e.offsetX, e.offsetY);  // 設定終點
    ctx.stroke();  // 依照設定開始繪製

    [lastX, lastY] = [e.offsetX, e.offsetY];  // 位置更新
    
    // 自動變色功能
    rainbow();
    // 自動粗細變化功能
    telescopicWidth();
}

我們先綁定各種滑鼠事件。
如果 mouseup 或是 mouseout 的時候就不允許繪製,
只有當 mousedown 的時候才會允許繪製並順便設定繪製起始點
(否則會從 左上角(0, 0) 連一條線到你點擊的位置)

這裡順便提一下設定起始點的 ES6 多變數指定寫法
ES6+: [a, c] = [b, d];
ES5: a = b; c = d;

if(!isDrawing) return;

而不管允不允許繪製,mousemove 時都一律執行繪製函數,
所以在函數內第一步驟先判斷是否允許繪製。

下方的進階功能我們下一步驟會開始說明

接著就是繪製路線跟位置更新!
這時候你就可以以細線畫畫囉!

【第五步:彩色功能函數撰寫(2)】

/*---------- Rainbow 功能 ----------*/
let hue = 0; // 色相環度數從 0 開始 (的異世界!? XD)

function rainbow(){
    // 透過 context 的 strokeStyle 設定筆畫顏色
    ctx.strokeStyle = `hsl(${hue}, 100%, 50%)`;
    
    hue++; // 色相環 度數更新
    if (hue >= 360) {
        hue = 0;
    }
}

這裡使用 hsl 的原因是因為其中有 色相環 可以使用
從 0 開始我們就一步一步地往上加,
如果 到了 360度 的時候 則重新歸零!

這時候你就會發現你邊拖曳顏色就會跟著變化,很酷~

【第六步:動態筆觸粗細功能函數撰寫(3)】

/*---------- 動態筆觸 功能 ----------*/
/** 
 * for 筆觸大小。 
 *
 * true 為 "細到粗"
 * false 為"粗到細"
 */
let direction = true;
        
function telescopicWidth(){
    /* 如果 >=100 或者 <=1 則筆觸大小反向動作 */
    if (ctx.lineWidth >= 100 || ctx.lineWidth <= 1) {
        direction = !direction;
    }

    /* 筆觸粗細實作 */
    if (direction) {
        ctx.lineWidth++;
    } else {
        ctx.lineWidth--;
    }
}

direction 變數負責決定是要越來越粗還是越來越細
當筆觸我們設定達到 100 或 1 的時候就反向!
(※注意:筆觸最小面積為 1px,非 0 !!)

這樣我們就都完成啦~~~ (灑花!!

小北黑白講

沒有趕稿的壓力真的可以寫好寫滿輕鬆寫,
這系列是我第一次在網路上撰寫文章,
真的希望透過文章可以整理我自己的思緒讓自己可以更清晰,
也希望自己的文筆可以越來越好啦!
(我知道現在寫法跟排版頗爛... 請多多指教建議了!!)

其實做到這邊,我想挑戰看看切版切出小畫家的架構,
然後自製個網頁版的小畫家試試看了... 請大家期待XDDD


上一篇
Day 07:陣列習題 (2)
系列文
JavaScript 30 挑戰日誌8
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言